package com.dave.gd.core.rule.execute.rule.impl;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.commons.beanutils.PropertyUtils;

import com.dave.gd.common.exception.RtManagerException;
import com.dave.gd.common.log.ILogger;
import com.dave.gd.common.log.LoggerFactory;
import com.dave.gd.common.util.StringUtils;
import com.dave.gd.core.rule.RuleEvent;
import com.dave.gd.core.rule.exception.RuleRuntimeException;
import com.dave.gd.core.rule.execute.rule.IJavaCodeRuler;
import com.dave.gd.core.rule.intf.IRlmRuleIntf;

/**
 * 一个类一个规则的， 可以继承：SimpleJavaCodeRuler 实现 execute 方法
 *
 */
public abstract class SimpleJavaCodeRuler implements IJavaCodeRuler {
    
    private static final ILogger LOG = LoggerFactory.getLogger(SimpleJavaCodeRuler.class);
    
    public Boolean execute(IRlmRuleIntf rule, RuleEvent evt) {
        return execute("execute", rule, evt);
    }
    
    @Override
    final public Boolean execute(String methName, IRlmRuleIntf rule, RuleEvent evt) {
        Boolean result = false;
        if (!"execute".equals(methName)) {
            throw new RtManagerException("执行规则输入方法名错误，规则id@id", SimpleJavaCodeRuler.class,
                "execute", "IllegalAccessException", "id", rule == null ? "0"
                    : rule.getRuleId() + "");
        }
        
        Method meth = this.getMeth(methName, rule, evt);
        if (meth == null) {
            if (!"execute".equals(methName)) {
                throw new RtManagerException("执行规则输入方法名错误，方法不存在，规则id@id",
                    SimpleJavaCodeRuler.class, "execute", "IllegalAccessException", "id",
                    rule == null ? "0"
                        : rule.getRuleId() + "");
            }
        }
        if (meth != null) {
            InvocationTargetException exception = null;
            try {
                result = (Boolean) meth.invoke(this, evt.makeArgs(rule));
            } catch (RuleRuntimeException e) {
                throw e;
            } catch (IllegalArgumentException e) {
                LOG.error(rule == null ? "0"
                    : rule.getRuleId() + "", e);
                //                e.printStackTrace();
                throw new RtManagerException("执行规则输入参数类型错误，规则id@id", SimpleJavaCodeRuler.class,
                    "execute", "IllegalArgumentException", "id", rule == null ? "0"
                        : rule.getRuleId() + "");
            } catch (IllegalAccessException e) {
                LOG.error(rule == null ? "0"
                    : rule.getRuleId() + "", e);
                //                e.printStackTrace();
                throw new RtManagerException("执行规则输入参数执行错误，规则id@id", SimpleJavaCodeRuler.class,
                    "execute", "IllegalAccessException", "id", rule == null ? "0"
                        : rule.getRuleId() + "");
            } catch (InvocationTargetException e) {
                LOG.error(rule == null ? "0"
                    : rule.getRuleId() + "", e);
                //                e.printStackTrace();
                exception = e;
            }
            if (exception != null && exception.getTargetException() != null) {
                if (exception.getTargetException() instanceof RuleRuntimeException) {
                    throw (RuleRuntimeException) exception.getTargetException();
                }
            }
            if (exception != null) {
                exception.printStackTrace();
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                exception.printStackTrace(pw);
                String msg = "";
                try {
                    if (PropertyUtils.isReadable((Throwable) exception, "targetException")) {
                        msg = PropertyUtils.getProperty((Throwable) exception, "targetException")
                            .toString();
                    }
                } catch (Exception ex) {
                    // just print the exception and continue
                    ex.printStackTrace();
                }
                throw new RtManagerException(msg, SimpleJavaCodeRuler.class, "excute",
                    StringUtils.isNullOrEmpty(sw) ? ""
                        : sw.toString());
                
            }
        }
        
        return result;
    }
    
    private Method getMeth(String methName, IRlmRuleIntf rule, RuleEvent evt) {
        Method[] meths = this.getClass().getMethods();
        
        for (Method meth : meths) {
            
            if (methName.equalsIgnoreCase(meth.getName()) == false) {
                continue;
            }
            
            return meth;
            // meth.get
        }
        
        return null;
        // this.getClass().getMethod(methName,evt.makeArgs(rule));
    }
    
}
